// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
// This source file is part of the Cangjie project, licensed under Apache-2.0
// with Runtime Library Exception.
//
// See https://cangjie-lang.cn/pages/LICENSE for license information.

#include "Rules/MatchRule.h"
#include "Rules/CallExprMatchRule.h"
#include "Rules/MemberAccessMatchRule.h"
#include "Rules/RefExprMatchRule.h"
#include "Rules/TypeNameMatchRule.h"
#include "Rules/LetAsPatternMatchRule.h"
#include "NodeCast.h"

#include "Rules/RuleList.h"

namespace CangjieMigrator::Rules {

RuleList::RuleList(const TomlFile &toml)
{
    for (const auto &config : toml.configs) {
        auto rule = Rule::TryCreate(*config.get());
        if (rule) {
            ruleMap[rule->matchRule->GetType()].emplace_back(rule.get());
            rules.emplace_back(std::move(rule));
        }
    }
}

bool RuleList::IsEmpty() const
{
    return rules.empty();
}

template <MatchRule::Type type, typename TMatchRule, typename U>
bool RuleList::Check(UpdateInstance::File &file, const Cangjie::AST::Node &node, const PositionRange &range) const
{
    auto extractedInfo = TMatchRule::ExtractInfo(node, range);
    if (!extractedInfo || extractedInfo->GetType() != type) {
        return false;
    }

    for (const auto rule : Get(type)) {
        if (!rule->matchRule->MatchConditions(extractedInfo.get())) {
            continue;
        }

        file.Add(rule); // Add matched rule
        auto actions = rule->GenerateAction(file, *extractedInfo);
        for (const auto &action : actions) { // Add actions
            file.Add(action);
        }
        return true;
    }
    return false;
}

void RuleList::Check(UpdateInstance::File &file, const Cangjie::AST::Node &node, const PositionRange &range) const
{
    if (node.astKind == Cangjie::AST::ASTKind::PACKAGE_SPEC) {
        file.Add(Cast<Cangjie::AST::ASTKind::PACKAGE_SPEC>(node), range);
        return;
    }
    if (node.astKind == Cangjie::AST::ASTKind::IMPORT_SPEC) {
        file.Add(Cast<Cangjie::AST::ASTKind::IMPORT_SPEC>(node), range);
        return;
    }
    if (Check<MatchRule::Type::CallExpr, CallExprMatchRule>(file, node, range)) {
        return;
    }
    if (Check<MatchRule::Type::MemberAccess, MemberAccessMatchRule>(file, node, range)) {
        return;
    }
    if (Check<MatchRule::Type::RefExpr, RefExprMatchRule>(file, node, range)) {
        return;
    }
    if (Check<MatchRule::Type::TypeName, TypeNameMatchRule>(file, node, range)) {
        return;
    }
    if (Check<MatchRule::Type::LetAsPattern, LetAsPatternMatchRule>(file, node, range)) {
        return;
    }
}

const std::vector<std::unique_ptr<Rule>> &RuleList::Get() const
{
    return rules;
}

const std::vector<const Rule *> &RuleList::Get(MatchRule::Type type) const
{
    static const std::vector<const Rule *> empty{};
    if (ruleMap.find(type) == ruleMap.end()) {
        return empty;
    }
    return ruleMap.at(type);
}

} // namespace CangjieMigrator::Rules
